package com.example.demo.utils;

/**
 * @author Lucy
 * @create 2024-03-15 21:01
 */
import com.example.demo.mapper.entity.Recommendation;
import com.example.demo.mapper.entity.UserAdClicks;
import com.example.demo.mapper.entity.UserFeature;

import java.util.*;

public class UserBasedCF {

    public static List<Recommendation> recommendAds(List<UserAdClicks> allClicks, UserFeature targetUser, int topN) {
        //每个广告被点击的次数
        Map<Integer, Integer> adClickCountMap = new HashMap<>();
        //每个用户点击每个广告的次数
        Map<Integer, Integer> userAdClickCountMap = new HashMap<>();

        // 计算广告点击次数
        for (UserAdClicks userAdClicks : allClicks) {
            adClickCountMap.put(userAdClicks.getAdId(), adClickCountMap.getOrDefault(userAdClicks.getAdId(), 0) + 1);
            if (userAdClicks.getStudentId() == targetUser.getStudentId()) {
                userAdClickCountMap.put(userAdClicks.getAdId(), userAdClickCountMap.getOrDefault(userAdClicks.getAdId(), 0) + 1);
            }
        }

        List<Recommendation> recommendations = new ArrayList<>();

        // 计算广告相似度并排序
        for (int adId : adClickCountMap.keySet()) {
            double similarity = calculateSimilarity(targetUser, getUserAdClicksForAdId(allClicks, adId));
            recommendations.add(new Recommendation(adId, similarity));
        }

        recommendations.sort(Comparator.comparing(Recommendation::getSimilarity).reversed());

        // 返回前topN个推荐
        return recommendations.subList(0, Math.min(topN, recommendations.size()));
    }

    private static UserAdClicks getUserAdClicksForAdId(List<UserAdClicks> allClicks, int adId) {
        for (UserAdClicks userAdClicks : allClicks) {
            if (userAdClicks.getAdId() == adId) {
                return userAdClicks;
            }
        }
        return null;
    }

    private static double calculateSimilarity(UserFeature targetUser, UserAdClicks userAdClicks) {
        double[] x = {targetUser.getGender(), targetUser.getCollegeId(), targetUser.getNativePlace()};
        double[] y = {userAdClicks.getGender(), userAdClicks.getCollegeId(), userAdClicks.getNativePlace()};

        return calculatePearsonCorrelation(x, y);
    }

    private static double calculatePearsonCorrelation(double[] x, double[] y) {
        double sumXY = 0;
        double sumX = 0;
        double sumY = 0;
        double sumXSquare = 0;
        double sumYSquare = 0;
        int n = x.length;

        for (int i = 0; i < n; i++) {
            sumXY += x[i] * y[i];
            sumX += x[i];
            sumY += y[i];
            sumXSquare += x[i] * x[i];
            sumYSquare += y[i] * y[i];
        }

        double numerator = (n * sumXY) - (sumX * sumY);
        double denominator = Math.sqrt((n * sumXSquare - sumX * sumX) * (n * sumYSquare - sumY * sumY));

        if (denominator == 0) {
            return 0; // 避免除零错误
        } else {
            return numerator / denominator;
        }
    }
}

